package public

import (
	"fmt"
	"github.com/e421083458/golang_common/lib"
	"github.com/garyburd/redigo/redis"
	"log"
	"sync/atomic"
	"time"
)

type RedisFlowCountService struct {
	ServiceName string
	Interval    time.Duration
	QPS         int64 // QPS 请求量
	Unix        int64
	TickerCount int64
	TotalCount  int64 // 日请求量
}

func NewRedisFlowCountService(ServiceName string, interval time.Duration) *RedisFlowCountService {
	reqCounter := &RedisFlowCountService{
		ServiceName: ServiceName,
		Interval:    interval,
		QPS:         0,
		Unix:        0,
	}
	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(err)
			}
		}()
		// 创建一个定时器，每隔interval执行一次
		ticker := time.NewTicker(interval)
		for {
			<-ticker.C
			tickerCount := atomic.LoadInt64(&reqCounter.TickerCount) //获取数据
			atomic.StoreInt64(&reqCounter.TickerCount, 0)            //重置数据
			// 获取当前时间
			currentTime := time.Now()
			// 获取Redis Key，每天和每小时的
			dayAppKey := reqCounter.GetDayKey(currentTime)
			hourAppKey := reqCounter.GetHourKey(currentTime)
			// 执行管道命令，增加计数
			if err := RedisConfPipline(func(c redis.Conn) {
				// 增加计数，并设置过期时间
				c.Send("INCRBY", dayAppKey, tickerCount)
				c.Send("EXPIRE", dayAppKey, 86400*2)
				c.Send("INCRBY", hourAppKey, tickerCount)
				c.Send("EXPIRE", hourAppKey, 86400*2)
			}); err != nil {
				log.Fatalf("向redis中存储数据出现错误：%s", err.Error())
				continue
			}
			// 从Redis中获取计数
			totalCount, err := reqCounter.GetDayData(currentTime)
			if err != nil {
				log.Fatalf("从redis中获取数据出现错误：%s", err.Error())
				continue
			}
			// 获取当前时间戳
			nowUnix := time.Now().Unix()
			if reqCounter.Unix == 0 {
				reqCounter.Unix = time.Now().Unix()
				continue
			}
			tickerCount = totalCount - reqCounter.TotalCount
			if nowUnix > reqCounter.Unix {
				reqCounter.TotalCount = totalCount
				reqCounter.QPS = tickerCount / (nowUnix - reqCounter.Unix)
				reqCounter.Unix = time.Now().Unix()
			}
		}
	}()
	return reqCounter
}

// 组装存储到Redis中的Key，每天
func (o *RedisFlowCountService) GetDayKey(t time.Time) string {
	dayStr := t.In(lib.TimeLocation).Format("20060102")
	redisKey := fmt.Sprintf("%s_%s_%s", RedisFlowDayKey, dayStr, o.ServiceName)
	return redisKey
}

// 组装存储到Redis中的Key，每时
func (o *RedisFlowCountService) GetHourKey(t time.Time) string {
	hourStr := t.In(lib.TimeLocation).Format("2006010215")
	redisKey := fmt.Sprintf("%s_%s_%s", RedisFlowHourKey, hourStr, o.ServiceName)
	return redisKey
}

// 从Redis中获取每小时的数据
func (o *RedisFlowCountService) GetHourData(t time.Time) (int64, error) {
	return redis.Int64(RedisConfDo("GET", o.GetHourKey(t)))
}

// 从Redis中获取全天的数据
func (o *RedisFlowCountService) GetDayData(t time.Time) (int64, error) {
	return redis.Int64(RedisConfDo("GET", o.GetDayKey(t)))
}

// 原子增加
func (o *RedisFlowCountService) Increase() {
	go func() {
		defer func() {
			if err := recover(); err != nil {
				fmt.Println(err)
			}
		}()
		atomic.AddInt64(&o.TickerCount, 1)
	}()
}
